package store

import (
	"context"
	"rank/internal/entity"

	"github.com/redis/go-redis/v9"
	"github.com/spf13/cast"
)

const (
	activityKey    = "rank:activity:{1001}"
	activityBanKey = "rank:activity:{1001}:ban"
	partRange      = 10
)

type Rank interface {
	// Ranking 获取指定玩家的名次
	Ranking(ctx context.Context, PID string) (*entity.Player, error)

	// Notice 将玩家信息更新到 ZSET
	Notice(ctx context.Context, p *entity.Player) error

	// PageMember 分页查询玩家信息
	PageMember(ctx context.Context, page int64, pageSize int64) ([]*entity.Player, int, error)

	// PartRank 获取当前玩家名次 ±10 内的局部榜单信息
	PartRank(ctx context.Context, PID string) ([]*entity.Player, error)
}

func (d *daoImpl) Ranking(ctx context.Context, PID string) (*entity.Player, error) {
	val, err := d.redisRepo.ZRevRank(ctx, activityKey, PID).Result()
	if err != nil {
		return nil, err
	}

	p := &entity.Player{Ranking: val}
	return p, nil
}

func (d *daoImpl) Notice(ctx context.Context, p *entity.Player) error {
	score := p.MarshalScore()
	return d.redisRepo.ZAdd(ctx, activityKey, redis.Z{Score: float64(score), Member: p.PID}).Err()
}

func (d *daoImpl) PageMember(ctx context.Context, page int64, pageSize int64) ([]*entity.Player, int, error) {
	start := pageSize*(page-1) + 1 // 跳过第一个
	end := pageSize * page
	data, err := d.redisRepo.ZRevRangeWithScores(ctx, activityKey, start, end).Result()
	if err != nil {
		return nil, 0, err
	}

	players := make([]*entity.Player, 0, len(data))
	for i, v := range data {
		p := &entity.Player{
			PID:     cast.ToString(v.Member),
			Ranking: start + int64(i),
		}
		p.UnmarshlScore(int64(v.Score))
		players = append(players, p)
	}

	total, err := d.redisRepo.ZCard(ctx, activityKey).Result()
	if err != nil {
		return nil, 0, err
	}

	return players, int(total - 1), nil
}

func (d *daoImpl) PartRank(ctx context.Context, PID string) ([]*entity.Player, error) {
	val, err := d.redisRepo.ZRevRank(ctx, activityKey, PID).Result()
	if err != nil {
		return nil, err
	}

	start := val - partRange
	if start < 1 {
		start = 1
	}

	end := start + partRange*2

	data, err := d.redisRepo.ZRevRangeWithScores(ctx, activityKey, start, end).Result()
	if err != nil {
		return nil, err
	}

	players := make([]*entity.Player, 0, len(data))
	for i, v := range data {
		p := &entity.Player{
			PID:     cast.ToString(v.Member),
			Ranking: start + int64(i),
		}
		p.UnmarshlScore(int64(v.Score))
		players = append(players, p)
	}

	return players, nil

}
